package main

import (
	"bytes"
	"errors"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"regexp"
	"strings"
	"text/template"

	// Log "github.com/tsif/component/log"
	"github.com/tsif/utils"
)

const (
	// 类型标记
	FIELD_TYPE_UNKOWN = 0 // 未知
	FIELD_TYPE_BOOL   = 1
	FIELD_TYPE_BYTE   = 2
	FIELD_TYPE_CHAR   = 3
	FIELD_TYPE_SHORT  = 4
	FIELD_TYPE_INT    = 5
	FIELD_TYPE_LONG   = 6
	FIELD_TYPE_FLOAT  = 7
	FIELD_TYPE_DOUBLE = 8
	FIELD_TYPE_STRING = 9
	FIELD_TYPE_DATE   = 10 // 日期
	FIELD_TYPE_UBYTE  = 11
	FIELD_TYPE_USHORT = 12
	FIELD_TYPE_UINT   = 13
	FIELD_TYPE_ULONG  = 14
)

var field_type_names = []string{"unkown",
	"bool", "byte", "char",
	"short", "int", "long",
	"float", "double",
	"string", "date",
	"ubyte", "ushort", "uint", "ulong"}

var field_type_default = []string{"unkown",
	"bool", "byte", "char",
	"int16", "int", "int64",
	"float", "double",
	"string", "time.Time",
	"uint8", "uint16", "uint32", "uint64"}

// 变量属性
type MakerField struct {
	Name    string //变量名
	Type    int    // 类型
	IsArray bool   //是否是数组
	Note    string // 注释
}

// 构建订单
type MakerOrder struct {
	Name string // 订单名
	Note string // 注释

	Fields    []MakerField                 // 变量属性
	Params    map[string]string            // 额外参数
	Caches    map[string]string            // 缓存数据
	CacheMaps map[string]map[string]string // 缓存表数据

	OutFileName string // 输出文件

	typeNameMap map[int]string // 类型名称
}

// 初始化类型表
func initOrder(order *MakerOrder) error {
	// 初始化
	order.OutFileName = order.Name + ".out"
	order.Caches = make(map[string]string)
	order.CacheMaps = make(map[string]map[string]string)
	// 检测模板
	if order.Params == nil {
		order.Params = make(map[string]string)
	}
	// 初始化typename表
	order.typeNameMap = make(map[int]string)
	for k, t := range field_type_default {
		order.typeNameMap[k] = t
	}
	return nil
}

// 根据类型名获取类型
func GetTypeByName(typename string) int {
	for k, tname := range field_type_names {
		if tname == typename {
			return k // 就是这种类型
		}
	}
	return FIELD_TYPE_UNKOWN
}

// 获取类型
func (this *MakerOrder) GetTypeName(dtype int, isarray bool) string {
	tname := field_type_default[FIELD_TYPE_UNKOWN]
	if this.typeNameMap != nil {
		// 提取内容
		t, ok := this.typeNameMap[dtype]
		if ok {
			tname = t
		}
	}
	// 判断是否是数组
	if isarray {
		return "[]" + tname
	}
	// Log.Info("get typename", dtype, "=", tname)
	return tname
}

// 创建模板自定义函数列表
func createFuncMap(order *MakerOrder) *template.FuncMap {
	// 获取参数(order的额外参数), 如果参数不存在则返回默认值
	func_param := func(key string, def string) string {
		if order.Params[key] == "" {
			return def
		}
		return order.Params[key]
	}
	// 获取变量的类型名
	func_typename := func(field MakerField) string {
		return order.GetTypeName(field.Type, field.IsArray)
	}
	// 设置类型的类型名
	func_settypename := func(typename string, showname string) string {
		dtype := GetTypeByName(typename)
		if dtype == FIELD_TYPE_UNKOWN {
			return "set unkown typename : " + typename
		}
		order.typeNameMap[dtype] = showname
		return ""
	}
	// 正则匹配算法
	func_regxcompile := func(str string, regx string) string {
		r := regexp.MustCompile(regx)
		// result := r.FindAllStringSubmatch(str, -1)
		return r.FindString(str)
	}
	// 首字母大写
	func_fristupper := func(str string) string {
		return utils.FirstUpper(str)
	}
	// 字符串小写
	func_tolower := func(str string) string {
		return strings.ToLower(str)
	}
	// 字符串大写
	func_toupper := func(str string) string {
		return strings.ToUpper(str)
	}
	// 首字母小写
	func_fristlower := func(str string) string {
		return utils.FirstLower(str)
	}
	// 写入缓存数组
	func_setcachemap := func(name string, key string, value string) string {
		cache, ok := order.CacheMaps[name]
		if !ok {
			cache = make(map[string]string)
			order.CacheMaps[name] = cache
		}
		cache[key] = value
		return ""
	}
	// 获取缓存表
	func_cachemap := func(name string) map[string]string {
		m, ok := order.CacheMaps[name]
		if !ok {
			return nil
		}
		return m
	}
	// 缓存表设置
	func_setcache := func(name string, value string) string {
		order.Caches[name] = value
		return ""
	}
	// 获取缓存数据
	func_cache := func(name string, defaultValue string) string {
		v, ok := order.Caches[name]
		if !ok || v == "" {
			return defaultValue
		}
		return order.Caches[name]
	}
	// 换行符
	func_lineend := func() string {
		return "\n"
	}
	// 设置输出文件名
	func_setfilename := func(filename string) string {
		order.OutFileName = filename
		return ""
	}

	return &template.FuncMap{"param": func_param,
		"regxcompile": func_regxcompile,
		"lineend":     func_lineend,
		"setfilename": func_setfilename,
		"fristupper":  func_fristupper,
		"fristlower":  func_fristlower,
		"tolower":     func_tolower,
		"toupper":     func_toupper,
		"setcache":    func_setcache,
		"cache":       func_cache,
		"setcachemap": func_setcachemap,
		"cachemap":    func_cachemap,
		"typename":    func_typename,
		"settypename": func_settypename}
}

// 输出模板内容
func showTemplateBody(teplBoby string) string {
	lineStrs := strings.Split(teplBoby, "\n")
	// 输出
	var buffer bytes.Buffer
	for l, str := range lineStrs {
		buffer.WriteString(fmt.Sprint(l + 1))
		buffer.WriteString(":")
		buffer.WriteString(str)
		buffer.WriteString("\n")
	}
	return buffer.String()
}

// 模板渲染
func MakeFile(order *MakerOrder, tempFiles []string, outPath string) error {
	// Log.Info("run", tempFiles, outPath)

	// 初始化
	err_i := initOrder(order)
	if err_i != nil {
		return err_i
	}

	//读取模板文件内容
	var buffer bytes.Buffer
	for _, tempFile := range tempFiles {
		// 读取文件
		fileBody, err_rf := ioutil.ReadFile(tempFile)
		if err_rf != nil {
			return errors.New("no find tempFile! " + tempFile) // 读取失败, 不存在文件
		}
		// 合并内容
		buffer.Write(fileBody)
	}
	tmplBody := buffer.String() // 模板内容

	// 模板内容特殊处理
	tmplBody = strings.Replace(tmplBody, "\r\n", "\n", -1)
	// tmplBody = strings.Replace(tmplBody, "}}\n{{", "}}{{", -1)
	tmplBody = strings.Replace(tmplBody, "}}\n", "}}", -1)
	// Log.Infof("tmplBody\n%s", showTemplateBody(tmplBody)) // 测试输出

	// 新建模板
	t := template.New("maker")
	// 添加自定义函数
	t.Funcs(*createFuncMap(order))

	// 进行模板读取
	// t, err_p := t.ParseFiles(tempFile)
	t, err_p := t.Parse(tmplBody)
	if err_p != nil {
		return errors.New(fmt.Sprintf("parse file=%s err=%s\n%s", tempFiles, err_p.Error(),
			showTemplateBody(tmplBody)))
	}

	// 创建输出数据缓存
	outBuf := new(bytes.Buffer)

	// 执行模板处理
	err_e := t.Execute(outBuf, order)
	if err_e != nil {
		return errors.New(fmt.Sprint("There was an error:", err_e.Error()))
	}
	outStr := outBuf.String()

	// 计算输出文件
	outFilePath := outPath + "/" + order.OutFileName
	outFilePath = strings.Replace(outFilePath, "\\", "/", -1)
	outFilePath = strings.Replace(outFilePath, "//", "/", -1)

	// 路径检测
	filedir, err_f := filepath.Abs(filepath.Dir(outFilePath))
	if err_f != nil {
		return err_f
	}
	// 如果文件夹不存在则创建
	utils.FolderNoCreate(filedir)

	// 打开文件
	file, err_o := os.OpenFile(outFilePath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
	if err_o != nil {
		return errors.New(fmt.Sprintf("open outfile fail! outfile=%s.\n", outFilePath))
	}
	defer file.Close()

	// 写入文件
	file.WriteString(outStr)

	return nil
}
